/*
 * Copyright (C) 2007  Vianney le Clément
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package fsahoraires.programmes;

import java.util.*;

import fsahoraires.cours.Cours;
import fsahoraires.cours.CoursManager;

public class Programme implements Iterable<Semestre> {

	private SortedSet<Semestre> semestres;
	private CoursManager manager;

	private List<ProgrammeListener> listeners = new ArrayList<ProgrammeListener>();

	public void addProgrammeListener(ProgrammeListener listener) {
		listeners.add(listener);
	}

	public void removeProgrammeListener(ProgrammeListener listener) {
		listeners.remove(listener);
	}

	private void fireAdded(Semestre semestre) {
		for (ProgrammeListener listener : listeners)
			listener.added(this, semestre);
	}

	private void fireRemoved(Semestre semestre) {
		for (ProgrammeListener listener : listeners)
			listener.removed(this, semestre);
	}

	public Programme() {
		semestres = new TreeSet<Semestre>();
		manager = new CoursManager();
	}

	/**
	 * Ajoute un semestre au programme
	 * 
	 * @param semestre
	 * @return true si le semestre a été ajouté, false s'il existait déjà
	 */
	boolean add(Semestre semestre) {
		if (semestres.contains(semestre))
			return false;
		semestres.add(semestre);
		fireAdded(semestre);
		return true;
	}

	void remove(Semestre semestre) {
		semestres.remove(semestre);
		fireRemoved(semestre);
	}

	public Semestre get(Semestre semestre) {
		return get(semestre.getAnnee(), semestre.getSemestre());
	}

	public Semestre get(int annee, int semestre) {
		for (Semestre sem : semestres) {
			if (sem.getAnnee() == annee && sem.getSemestre() == semestre)
				return sem;
		}
		return null;
	}

	public Iterator<Semestre> iterator() {
		return semestres.iterator();
	}

	/**
	 * @return la somme totale de crédits dans ce programme
	 */
	public float getCredits() {
		/*
		 * Pour éviter de comptabiliser 2 fois le même cours, mais dans des
		 * semestres différents, récupérer d'abord la liste des cours de chaque
		 * semestre et le mettre dans un Set qui ignore les doublons.
		 */
		Set<Cours> cours = new HashSet<Cours>();
		for (Semestre semestre : this)
			cours.addAll(semestre.getCours());
		float credits = 0;
		for (Cours c : cours)
			credits += c.getCredits();
		return credits;
	}

	/**
	 * @param cours
	 * @return le nombre de semestre qu'un cours est inscrit
	 */
	public int getSemestresCount(Cours cours) {
		int count = 0;
		for (Semestre s : this) {
			if (s.getCours().contains(cours))
				count++;
		}
		return count;
	}

	/**
	 * Nettoye la cache de tous les cours non pris.
	 */
	public void cleanCache() {
		for (Cours cours : manager) {
			if (getSemestresCount(cours) == 0)
				cours.dispose();
		}
	}

	public CoursManager getManager() {
		return manager;
	}

	public void close() {
		manager.close();
	}

}
